package com.ben.multiple.util;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import java.io.StringReader;
import java.io.StringWriter;

/**
 * 简单对象和 Xml字符串 相互转换
 *
 * @author ben
 * @date 2019/4/2
 */
public interface ObjectAndXmlMapper {

    /**
     * 将对象转换成xml字符串，属性值为null的属性和值会被忽略。  xml没有首行,字符编码 utf-8; xml 格式：换行和缩进
     *
     * @param object 在对象上要加上此注解@XmlRootElement(name = "xml")
     * @return String
     * @throws JAXBException JAXBException
     */
    static String convertObjectToXml(Object object) throws JAXBException {
        if (object == null) {
            return null;
        }
        //获取一个jaxbContext对象，绑定object
        JAXBContext jaxbContext = JAXBContext.newInstance(object.getClass());
        //创建一个Marshaller对象，用于将object转换成xml
        Marshaller marshaller = jaxbContext.createMarshaller();
        //设置字符
        marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        //去掉首行：不包含<?xml version="1.0" encoding="UTF-8"?>
        marshaller.setProperty(Marshaller.JAXB_FRAGMENT, true);
        //xml格式化：换行和缩进
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        //创建字符文件流，用于接收转换后的结果
        StringWriter writer = new StringWriter();
        marshaller.marshal(object, writer);
        return writer.toString();
    }

    /**
     * 将xml转换成对象，xml中的元素会一一对应类中的属性； xml中有的元素，类中没有时自动忽略； 类中有的属性，xml中没有时，结果是null；
     *
     * @param xmlString xml格式的字符串，有无首行不影响转换结果
     * @param type      Class
     * @param <T>       类型：泛型类；类上需要增加注解 @XmlRootElement(name = "xml")
     * @return T
     * @throws JAXBException JAXBException
     */
    @SuppressWarnings("unchecked")
    static <T> T convertXmlToObject(String xmlString, Class<T> type) throws JAXBException {
        if (xmlString == null || "".equals(xmlString) || type == null) {
            return null;
        }
        JAXBContext jaxbContext = JAXBContext.newInstance(type);
        //创建一个Unmarshaller对象，用于将xml转换成 T 对象
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        //通过字符输入流读取xml
        StringReader stringReader = new StringReader(xmlString);
        //将输入流读取的结果转化成对象
        Object object = unmarshaller.unmarshal(stringReader);
        return (T) object;
    }
}
